<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>View</title>
    <link rel="stylesheet" href="http://yui.yahooapis.com/3.4.0pr3/build/cssgrids/grids-min.css">
    <link rel="stylesheet" href="../assets/css/main.css">
    <link rel="stylesheet" href="../assets/vendor/prettify/prettify-min.css">
    <script src="../../build/yui/yui-min.js"></script>
</head>
<body>

<div id="doc">
    <h1>View</h1>

    
        <a href="#toc" class="jump">Jump to Table of Contents</a>
    

    <div class="yui3-g">
        <div id="main" class="yui3-u">
            <div class="content"><div class="intro">
<p>
A View represents a renderable piece of an application's user interface, and provides hooks for easily subscribing to and handling delegated DOM events on a view's container element.
</p>

<p>
Views provide a generic structure for template- or DOM-based rendering. Views are template-agnostic, meaning that there's no actual template language built in, so you're welcome to use any template language you want (or none at all).
</p>

<p>
A common practice is to associate a View instance with a <a href="../model/index.html">Model</a> instance so that the view is automatically re-rendered whenever the model changes, but this relationship is not required. A view may also be used standalone, associated with a <a href="../model-list/index.html">Model List</a>, or may even contain nested views.
</p>

<p>
The <code>Y.View</code> class is meant to be extended by a custom class that defines a custom <code>render()</code> method and any necessary DOM event handlers.
</p>
</div>

<h2 id="getting-started">Getting Started</h2>

<p>
To include the source files for View and its dependencies, first load
the YUI seed file if you haven't already loaded it.
</p>

<pre class="code prettyprint">&lt;script src=&quot;http:&#x2F;&#x2F;yui.yahooapis.com&#x2F;3.4.0&#x2F;build&#x2F;yui&#x2F;yui-min.js&quot;&gt;&lt;&#x2F;script&gt;</pre>


<p>
Next, create a new YUI instance for your application and populate it with the
modules you need by specifying them as arguments to the <code>YUI().use()</code> method.
YUI will automatically load any dependencies required by the modules you
specify.
</p>

<pre class="code prettyprint">&#x2F;&#x2F; Create a new YUI instance and populate it with the required modules.
YUI().use(&#x27;view&#x27;, function (Y) {
    &#x2F;&#x2F; View is available and ready for use. Add implementation
    &#x2F;&#x2F; code here.
});</pre>


<p>
For more information on creating YUI instances and on the
<a href="http://yuilibrary.com/yui/docs/api/classes/YUI.html#method_use"><code>use()</code> method</a>, see the
documentation for the <a href="../yui/index.html">YUI Global object</a>.
</p>


<h2 id="using-view">Using View</h2>

<h3 id="extending-yview">Extending <code>Y.View</code></h3>

<p>
The first step in creating a custom View class is to extend <code>Y.View</code>. This allows you to override the <code>render()</code> method and default View properties to implement the desired behavior for your view.
</p>

<p>
If you want, you can also establish a relationship between your view and a <a href="../model/index.html">Model</a> or <a href="../model-list/index.html">Model List</a> instance by attaching event handlers to them in a custom <code>initializer()</code> method. The initializer is also typically where you would subscribe to model change events to be notified when you need to re-render your view.
</p>

<p>
The <a href="#view-properties">View Properties</a> section below describes the properties available on the View class in more detail, but there are a couple of important properties worth mentioning up front:
</p>

<dl>
  <dt><code>container</code></dt>
  <dd>
    <p>
    A DOM element, <code>Y.Node</code> instance, or HTML string representing an element that will contain the view's rendered content. This element may already exist on the page, or it may be added to the page later; that's up to you.
    </p>

    <p>
    When rendering or re-rendering a view, the contents of this element will change, but the element itself won't be removed until you call the view's <code>remove()</code> method.
    </p>
  </dd>

  <dt><code>events</code></dt>
  <dd>
    <p>
    A map of CSS selectors to DOM events that should be handled by your view.
    </p>
  </dd>
</dl>

<p>
Views provide <a href="#view-properties">several other properties</a> as well, but these two are the most important, since they form the core of the view's functionality.
</p>

<p>
The following example demonstrates how to create a <code>Y.PieView</code> class that displays the current state of a <code>Y.PieModel</code> instance like the one defined in the <a href="../model/index.html">Model</a> user guide.
</p>

<pre class="code prettyprint">&#x2F;&#x2F; Create a new Y.PieView class that extends Y.View and renders the current
&#x2F;&#x2F; state of a Y.PieModel instance.
Y.PieView = Y.Base.create(&#x27;pieView&#x27;, Y.View, [], {
  &#x2F;&#x2F; Add prototype methods and properties for your View here if desired. These
  &#x2F;&#x2F; will be available to all instances of your View. You may also override
  &#x2F;&#x2F; existing default methods and properties of Y.View.

  &#x2F;&#x2F; Override the default container element.
  container: &#x27;&lt;div class=&quot;pie&quot;&#x2F;&gt;&#x27;,

  &#x2F;&#x2F; Provide a template that will be used to render the view. The template can
  &#x2F;&#x2F; be anything we want, but in this case we&#x27;ll use a string that will be
  &#x2F;&#x2F; processed with Y.Lang.sub().
  template: &#x27;{slices} slice(s) of {type} pie remaining. &#x27; +
            &#x27;&lt;a href=&quot;#&quot; class=&quot;eat&quot;&gt;Eat a Slice!&lt;&#x2F;a&gt;&#x27;,

  &#x2F;&#x2F; Specify delegated DOM events to attach to the container.
  events: {
    &#x27;.eat&#x27;: {click: &#x27;eatSlice&#x27;}
  },

  &#x2F;&#x2F; The initializer function will run when a view is instantiated. This is a
  &#x2F;&#x2F; good time to subscribe to change events on a model instance.
  initializer: function () {
    var model = this.model;

    &#x2F;&#x2F; Re-render this view when the model changes, and destroy this view when
    &#x2F;&#x2F; the model is destroyed.
    model.after(&#x27;change&#x27;, this.render, this);
    model.after(&#x27;destroy&#x27;, this.destroy, this);
  },

  &#x2F;&#x2F; The render function is responsible for rendering the view to the page. It
  &#x2F;&#x2F; will be called whenever the model changes.
  render: function () {
    &#x2F;&#x2F; Render this view&#x27;s HTML into the container element.
    this.container.setContent(Y.Lang.sub(this.template,
        this.model.getAttrs([&#x27;slices&#x27;, &#x27;type&#x27;])));

    &#x2F;&#x2F; Append the container element to the DOM if it&#x27;s not on the page already.
    if (!this.container.inDoc()) {
      Y.one(&#x27;body&#x27;).append(this.container);
    }
  },

  &#x2F;&#x2F; The eatSlice function will handle click events on this view&#x27;s &quot;Eat a Slice&quot;
  &#x2F;&#x2F; link.
  eatSlice: function (e) {
    e.preventDefault();

    &#x2F;&#x2F; Call the pie model&#x27;s eatSlice() function. This will consume a slice of
    &#x2F;&#x2F; pie (if there are any left) and update the model, thus causing the view
    &#x2F;&#x2F; to re-render.
    this.model.eatSlice();
  }
});</pre>


<p>
After defining the <code>Y.PieView</code> class and the <code>Y.PieModel</code> class (see the <a href="../model/index.html">Model</a> user guide), we can instantiate a new PieView and associate it with a PieModel instance.
</p>

<pre class="code prettyprint">var pie     = new Y.PieModel({type: &#x27;apple&#x27;}),
    pieView = new Y.PieView({model: pie});

pieView.render();</pre>


<p>
This renders the following HTML to the page:
</p>

<pre class="code prettyprint">&lt;div class=&quot;pie&quot;&gt;
  6 slice(s) of apple pie remaining. &lt;a href=&quot;#&quot; class=&quot;eat&quot;&gt;Eat a Slice!&lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;</pre>


<p>
If the user clicks the "Eat a Slice!" link, the model will be updated and the view will re-render itself:
</p>

<pre class="code prettyprint">&lt;div class=&quot;pie&quot;&gt;
  5 slice(s) of apple pie remaining. &lt;a href=&quot;#&quot; class=&quot;eat&quot;&gt;Eat a Slice!&lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;</pre>


<h3 id="view-properties">View Properties</h3>

<p>
View classes and subclasses contain the following properties.
</p>

<table>
  <thead>
    <tr>
      <th>Property</th>
      <th>Default Value</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code>container</code></td>
      <td><code>&#x27;&lt;div&#x2F;&gt;&#x27;</code></td>
      <td>
        <p>
        A DOM element, <code>Y.Node</code> instance, or HTML string representing an element that will contain the view's rendered content. The view's DOM events will be attached to this container so that they don't have to be re-attached if the view is re-rendered.
        </p>

        <p>
        If you specify a container element that isn't already on the page, then you'll need to append it to the page yourself. You can do this in the <code>render()</code> method the first time the view is rendered.
        </p>
      </td>
    </tr>

    <tr>
      <td><code>events</code></td>
      <td><code>{}</code></td>
      <td>
        <p>
          A map of CSS selectors to DOM events that should be handled by your view. Under the hood, event delegation is used so that the actual events are attached to the view's <code>container</code> element. This means you can freely re-render the contents of the container without having to worry about detaching and re-attaching events.
        </p>

        <p>
        See <a href="#handling-dom-events">Handling DOM Events</a> for more details.
        </p>
      </td>
    </tr>

    <tr>
      <td><code>model</code></td>
      <td><code>undefined</code></td>
      <td>
        <p>
        A <a href="../model/index.html">Model</a> instance that you want to associate with the view instance. This is meant to be set as a config property when a view is instantiated.
        </p>

        <p>
        This property is entirely optional. There's no requirement that views be associated with models, but if you do intend to associate your view with a model, then specifying that model instance at instantiation time will cause a reference to be stored here for convenience.
        </p>

        <p>
        For more information, see <a href="#associating-a-view-with-a-model-or-model-list">Associating a View with a Model or Model List</a>.
        </p>
      </td>
    </tr>

    <tr>
      <td><code>modelList</code></td>
      <td><code>undefined</code></td>
      <td>
        <p>
        A <a href="../model-list/index.html">Model List</a> instance that you want to associate with the view instance. This is meant to be set as a config property when a view is instantiated.
        </p>

        <p>
        Like the <code>model</code> property, the <code>modelList</code> property is entirely optional, and is provided for convenience only. For more information, see <a href="#associating-a-view-with-a-model-or-model-list">Associating a View with a Model or Model List</a>.
        </p>
      </td>
    </tr>

    <tr>
      <td><code>template</code></td>
      <td><code>&#x27;&#x27;</code></td>
      <td>
        <p>
        Reference to a template for this view.
        </p>

        <p>
        Much like the <code>model</code> property, this is a convenience property that has no default behavior of its own. It's only provided as a convention to allow you to store whatever you consider to be a template, whether that's an HTML string, a <code>Y.Node</code> instance, a Mustache template, or anything else your heart desires.
        </p>

        <p>
        How this template gets used is entirely up to you and your custom <code>render()</code> method. See <a href="#rendering-a-view">Rendering a View</a> for more details.
        </p>
      </td>
    </tr>
  </tbody>
</table>

<h3 id="handling-dom-events">Handling DOM Events</h3>

<p>
The <code>events</code> property of a view class allows you to specify a mapping of CSS selectors to DOM events that should be handled by your view.
</p>

<p>
Under the hood, event delegation is used so that the actual events are attached to the view's <code>container</code> element. This means you can freely re-render the contents of the container without having to worry about detaching and re-attaching events.
</p>

<p>
Event handlers may be specified as functions or as strings that map to function names on the view instance or its prototype.
</p>

<pre class="code prettyprint">var Y.MyView = Y.Base.create(&#x27;myView&#x27;, Y.View, [], {
  &#x2F;&#x2F; ... other prototype properties and methods ...

  events: {
    &#x2F;&#x2F; Call &#x60;this.toggle()&#x60; whenever the element with the id &quot;toggle-button&quot; is
    &#x2F;&#x2F; clicked.
    &#x27;#toggle-button&#x27;: {click: &#x27;toggle&#x27;},

    &#x2F;&#x2F; Call &#x60;this.hoverOn()&#x60; when the mouse moves over any element with the
    &#x2F;&#x2F; &quot;hoverable&quot; class, and &#x60;this.hoverOff()&#x60; when the mouse moves out of any
    &#x2F;&#x2F; element with the &quot;hoverable&quot; class.
    &#x27;.hoverable&#x27;: {
        mouseover: &#x27;hoverOn&#x27;,
        mouseout : &#x27;hoverOff&#x27;
    }
  },

  hoverOff: function (e) {
    &#x2F;&#x2F; ... handle the mouseout event ...
  },

  hoverOn: function (e) {
    &#x2F;&#x2F; ... handle the mouseover event ...
  },

  toggle: function (e) {
    &#x2F;&#x2F; ... handle the click event ...
  }
});</pre>


<p>
The <code>this</code> object in view event handlers will always refer to the current view instance. If you'd prefer <code>this</code> to refer to something else, use <code>Y.bind()</code> to bind a custom <code>this</code> object.
</p>

<p>
At instantiation time, you can provide an <code>events</code> config property to add or override event handlers for individual view instances.
</p>

<pre class="code prettyprint">&#x2F;&#x2F; Overriding or adding event handlers on a per-instance basis.
var myView = new Y.MyView({
  events: {
    &#x2F;&#x2F; Replace the #toggle-button click handler with a custom one.
    &#x27;#toggle-button&#x27;: {
      click: function (e) {
        &#x2F;&#x2F; ... custom click handler ...
      }
    },

    &#x2F;&#x2F; Add a handler for focus events on elements with the &quot;focusable&quot; class.
    &#x27;.focusable&#x27;: {
      focus: function (e) {
        &#x2F;&#x2F; ... custom focus handler ...
      }
    }
  }
});</pre>


<h3 id="rendering-a-view">Rendering a View</h3>

<p>
A view's default <code>render()</code> method is completely empty. It's up to you to override this method and fill it with your own rendering logic.
</p>

<p>
The ultimate goal of your <code>render()</code> function is to put some HTML into the view's <code>container</code> element and ensure that the container is on the page. How you choose to do this is entirely up to you.
</p>

<p>
You might choose to use plain old DOM manipulation to create the elements for your view, or you might store an HTML string in your view's <code>template</code> property and then render that, or you might even store a full-blown template (perhaps using <a href="http://www.handlebarsjs.com/">Handlebars</a> or <a href="http://mustache.github.com/">Mustache</a>). The View component intentionally avoids dictating how you render things, so you're free to do whatever you like best.
</p>

<p>
In general, it makes sense to <a href="#associating-a-view-with-a-model-or-model-list">associate a view with a Model or Model List instance</a> so that you can update the view when related data changes. You can do this either by re-rendering the entire view (this is the easiest way) or by modifying only the parts of the view that have changed (harder, but possibly more performant).
</p>

<p>
Again, which route you choose to take is entirely up to you.
</p>

<h3 id="associating-a-view-with-a-model-or-model-list">Associating a View with a Model or Model List</h3>

<p>
When instantiating a view, you may pass a <code>model</code> property in the config object that references a <a href="../model/index.html">Model</a> instance you wish to associate with the view.
</p>

<pre class="code prettyprint">&#x2F;&#x2F; Associate a PieModel instance with a PieView instance.
var pie     = new Y.PieModel({type: &#x27;apple&#x27;}),
    pieView = new Y.PieView({model: pie});</pre>


<p>
This property is entirely optional. There's no requirement that views be associated with models, but if you do intend to associate your view with a model, then specifying that model instance at instantiation time will cause a reference to be stored for convenience.
</p>

<p>
If you do set the <code>model</code> property, there's no special magic under the hood that will link the model to your view; you'll still need to manually subscribe to any model events you want to handle in your view's <code>initializer()</code> function (see the example in <a href="#extending-yview">Extending <code>Y.View</code></a>).
</p>

<p>
Instead of specifying a model association, you could also choose to associate your view with a <a href="../model-list/index.html">Model List</a>, or even with nothing at all. It's entirely up to you.
</p>

<p>
To associate a view with a <a href="../model-list/index.html">Model List</a> instead of a Model, you'll need to add a bit of extra logic to your view's <code>initializer()</code> method when defining your custom view class.
</p>

<pre class="code prettyprint">&#x2F;&#x2F; Create a custom View subclass that can be associated with a Model List.
var Y.PieListView = Y.Base.create(&#x27;pieListView&#x27;, Y.View, [], {
  &#x2F;&#x2F; ... other prototype properties and methods ...

  initializer: function (config) {
    if (config &amp;&amp; config.modelList) {
      &#x2F;&#x2F; Store the modelList config value as a property on this view instance.
      this.modelList = config.modelList;

      &#x2F;&#x2F; Re-render the view whenever a model is added to or removed from the
      &#x2F;&#x2F; model list, or when the entire list is refreshed.
      this.modelList.after([&#x27;add&#x27;, &#x27;remove&#x27;, &#x27;refresh&#x27;], this.render, this);
    }
  },

  &#x2F;&#x2F; ... other prototype properties and methods ...
});</pre>


<p>
You could then pass in a Model List instance when instantiating your view.
</p>

<pre class="code prettyprint">var pies        = new Y.PieList(),
    pieListView = new Y.PieListView({modelList: pies});

&#x2F;&#x2F; When we add a pie to the list, the view will be re-rendered.
pies.add({type: &#x27;banana cream&#x27;});</pre>


<h2 id="views-vs-widgets">Views vs. Widgets</h2>

<p>
While <code>Y.View</code> and <a href="../widget/index.html"><code>Y.Widget</code></a> may seem similar on the surface, they're intended for different purposes, even though they have some overlap.
</p>

<p>
In a nutshell: a view is meant to be used as an internal piece of a component or application, and is not intended to be exposed to external developers as an API or a reusable component itself. A widget, on the other hand, is meant to be a reusable component with a public API.
</p>

<p>
Views are well suited for rendering portions of web pages, whether large or small, since they're lightweight and can be easily associated with Models and Model Lists. A view may even be responsible for creating and rendering widgets on a page, but the view is an internal piece of an application or component and is not meant to be used externally.
</p>

<p>
Widgets are well suited for representing self-contained interactive controls or objects that behave like first-class HTML elements. A widget might actually use views to provide a visual representation and even handle some DOM events &mdash; but only as internal plumbing. The widget itself is responsible for providing a reusable public API.
</p>
</div>
        </div>

        <div id="sidebar" class="yui3-u">
            
                <div id="toc" class="sidebox">
                    <div class="hd">
                        <h2 class="no-toc">Table of Contents</h2>
                    </div>

                    <div class="bd">
                        <ul class="toc">
<li>
<a href="#getting-started">Getting Started</a>
</li>
<li>
<a href="#using-view">Using View</a>
<ul class="toc">
<li>
<a href="#extending-yview">Extending <code>Y.View</code></a>
</li>
<li>
<a href="#view-properties">View Properties</a>
</li>
<li>
<a href="#handling-dom-events">Handling DOM Events</a>
</li>
<li>
<a href="#rendering-a-view">Rendering a View</a>
</li>
<li>
<a href="#associating-a-view-with-a-model-or-model-list">Associating a View with a Model or Model List</a>
</li>
</ul>
</li>
<li>
<a href="#views-vs-widgets">Views vs. Widgets</a>
</li>
</ul>
                    </div>
                </div>
            

            

            
                <div class="sidebox">
                    <div class="hd">
                        <h2 class="no-toc">Examples That Use This Component</h2>
                    </div>

                    <div class="bd">
                        <ul class="examples">
                            
                                
                                    <li data-description="A basic todo list built with the Model, Model List, and View components.">
                                        <a href="../app/app-todo.html">Todo List</a>
                                    </li>
                                
                            
                        </ul>
                    </div>
                </div>
            
        </div>
    </div>
</div>

<script src="../assets/vendor/prettify/prettify-min.js"></script>
<script>prettyPrint();</script>

</body>
</html>
